package work.mediway.mdm.biz.service.patient.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mediway.hos.app.base.seure.util.SecurityUtils;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import work.mediway.mdm.core.page.QueryRequest;
import work.mediway.mdm.core.constant.MdmConstant;
import work.mediway.mdm.biz.dto.patient.PatientMergeDTO;
import work.mediway.mdm.biz.entity.patient.PaMergePatientLog;
import work.mediway.mdm.biz.entity.patient.PaSuspectPatient;
import work.mediway.mdm.biz.entity.patient.RelPatient;
import work.mediway.mdm.biz.mapper.patient.PaMergePatientLogMapper;
import work.mediway.mdm.biz.service.patient.PaMergePatientLogService;
import work.mediway.mdm.biz.service.patient.PaSuspectPatientService;
import work.mediway.mdm.biz.service.patient.RelPatientService;
import work.mediway.mdm.biz.vo.patient.PatientMergeListVO;
import work.mediway.mdm.biz.vo.patient.PatientMergeLogListVO;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2020/12/22
 */

@Slf4j
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
@Service
public class PaMergePatientLogServiceImpl extends ServiceImpl<PaMergePatientLogMapper, PaMergePatientLog> implements PaMergePatientLogService {

    private final RelPatientService relPatientService;
    private final PaSuspectPatientService suspectPatientService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void mergePatient(String majorPatPatientId, String minorPatPatientIds) {
        // 1、更新Rel_Patient表的引用 2、删除Suspect_Patient表中的对应数据(如果一个患者已经被作为主患者合并，那么他作为次患者的数据应删除) 3、记录合并日志
        List<String> minorPatPatientIdList = StrUtil.splitTrim(minorPatPatientIds, StringPool.PIPE);
        String[] date = StrUtil.splitToArray(DateUtil.now(), " ");
        log.info(StrUtil.format("将合并患者数量：【{}】, 主患者Id = 【{}】, 次患者Id = 【{}】", minorPatPatientIdList.size(), majorPatPatientId, minorPatPatientIdList.toString()));
        for (String patientId : minorPatPatientIdList) {
            // 在Rel_Patient表中将次患者的LinkPatientId设置为主患者Id
            RelPatient relPatient = new RelPatient();
            relPatient.setLinkPatientId(majorPatPatientId);
            relPatient.setLastUpdateDate(date[0]);
            relPatient.setLastUpdateTime(date[1]);
            LambdaUpdateWrapper<RelPatient> updateWrapper = Wrappers.lambdaUpdate(RelPatient.class);
            this.relPatientService.update(relPatient, updateWrapper.eq(RelPatient::getPatPatientId, patientId));
            /// 如果一个患者已经被作为主患者合并，那么他作为次患者的数据应删除, 同时删除该条合并信息
            LambdaUpdateWrapper<PaSuspectPatient> update = Wrappers.lambdaUpdate(PaSuspectPatient.class);
            update.eq(PaSuspectPatient::getSuspectPatPatientId, majorPatPatientId)
                    .eq(PaSuspectPatient::getSuspectRelPatPatientId, patientId);
            suspectPatientService.remove(update);
            update.clear();
            update.eq(PaSuspectPatient::getSuspectRelPatPatientId, majorPatPatientId);
            suspectPatientService.remove(update);
            // 如果一个患者被作为次患者合并了，那么他也不能再次作为主患者, 同时也不能作为其他的次患者
            update.clear();
            update.eq(PaSuspectPatient::getSuspectPatPatientId, patientId);
            suspectPatientService.remove(update);
            update.clear();
            update.eq(PaSuspectPatient::getSuspectRelPatPatientId, patientId);
            suspectPatientService.remove(update);
            // 记录合并日志
            saveMergeLog(patientId, majorPatPatientId, MdmConstant.PATIENT_MERGE_STATUS);
        }
    }

    @Override
    public Page<PatientMergeLogListVO> pageMergePatientLog(PatientMergeDTO mergeDTO, QueryRequest queryRequest) {
        /*if (StrUtil.isBlank(mergeDTO.getPatMergeStatus())) {
            mergeDTO.setPatMergeStatus(MdmConstant.PATIENT_MERGE_STATUS);
        }*/
        Page<PatientMergeLogListVO> page = new Page<>(queryRequest.getCurrent(), queryRequest.getSize());
        page.setOrders(OrderItem.descs("mergeUpdateDate", "mergeUpdateTime"));
        page.setRecords(this.baseMapper.pageMergePatientLog(null, mergeDTO));

        for (PatientMergeLogListVO record : page.getRecords()) {
            record.setMergeUpdateDateTime(record.getMergeUpdateDate() + StringPool.SPACE + record.getMergeUpdateTime());
        }
        return page;
    }

    @Override
    public List<PatientMergeListVO> pageMergePatient(PatientMergeDTO mergeDTO, QueryRequest queryRequest) {
        List<PatientMergeListVO> result = CollUtil.newArrayList();
        // 查询合并列表，如果患者被合并过一次但是取消了，不再显示；如果再次合并，显示
        mergeDTO.setPatMergeStatus(MdmConstant.PATIENT_MERGE_STATUS);
        Page<PatientMergeLogListVO> page = new Page<>(queryRequest.getCurrent(), queryRequest.getSize());
        page.setOrders(OrderItem.descs("UpdateDate", "UpdateTime"));
        page.setRecords(this.baseMapper.pageMergePatientList(page, mergeDTO));

        page.getRecords().forEach(item -> {
            PatientMergeListVO vo = BeanUtil.copyProperties(item, PatientMergeListVO.class);
            vo.setMergeUpdateDateTime(StrUtil.join(" ", item.getMergeUpdateDate(), item.getMergeUpdateTime()));
            result.add(vo);
        });
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void mergeCancelPatient(String mergePatOldPatientId, String mergePatPatientId) {
        // 1、更新Rel_Patient表的引用 2、从新计算两者的相似度然后插入Suspect_Patient表 3、记录取消合并日志
        String[] date = StrUtil.splitToArray(DateUtil.now(), " ");
        RelPatient relPatient = new RelPatient();
        relPatient.setLinkPatientId("");
        relPatient.setLastUpdateDate(date[0]);
        relPatient.setLastUpdateTime(date[1]);
        this.relPatientService.update(relPatient, Wrappers.lambdaUpdate(RelPatient.class).eq(RelPatient::getPatPatientId, mergePatOldPatientId));
        // 从新计算两者的相似度然后插入Suspect_Patient表
        List<PaSuspectPatient> suspectPatients = this.suspectPatientService.computeSuspect(mergePatPatientId, mergePatOldPatientId);
        // 存储
        this.suspectPatientService.saveSuspect(suspectPatients);
        // 记录合并日志
        saveMergeLog(mergePatOldPatientId, mergePatPatientId, MdmConstant.PATIENT_MERGE_CANCEL_STATUS);
    }

    /**
     * 记录合并日志
     *
     * @param mergePatOldPatientId     合并前Id
     * @param mergePatPatientId        合并后Id
     * @param patientMergeCancelStatus 合并状态
     */
    private void saveMergeLog(String mergePatOldPatientId, String mergePatPatientId, String patientMergeCancelStatus) {
        PaMergePatientLog mergePatientLog = new PaMergePatientLog();
        mergePatientLog.setMergePatOldPatientId(mergePatOldPatientId);
        mergePatientLog.setMergePatPatientId(mergePatPatientId);
        mergePatientLog.setMergeUserId(SecurityUtils.getLoginName());
        mergePatientLog.setMergeStatus(patientMergeCancelStatus);
        mergePatientLog.setOpsSourceSystemCode(MdmConstant.SYSTEM_NAME);
        String[] dateTime = StrUtil.splitToArray(DateUtil.now(), " ");
        mergePatientLog.setMergeUpdateDate(dateTime[0]);
        mergePatientLog.setLastUpdateDate(dateTime[0]);
        mergePatientLog.setMergeUpdateTime(dateTime[1]);
        mergePatientLog.setLastUpdateTime(dateTime[1]);
        this.save(mergePatientLog);
    }
}
